package com.baiye.www.spring.aop;

import com.baiye.www.spring.aop.advisor.AspectJExpressionPointcutAdvisor;
import com.baiye.www.spring.aop.factory.ProxyFactory;
import com.baiye.www.spring.ioc.BeanPostProcessor;
import com.baiye.www.spring.ioc.factory.BeanFactory;
import com.baiye.www.spring.ioc.factory.BeanFactoryAware;
import com.baiye.www.spring.ioc.factory.XmlBeanFactory;
import org.aopalliance.intercept.MethodInterceptor;

import java.util.List;

/**
 * AOP 与 IOC 桥梁类
 *
 * @author baiye
 * @version 1.0
 * @date 2021/12/12 14:57
 */
public class AspectJAwareAdvisorAutoProxyCreator implements BeanPostProcessor, BeanFactoryAware {

    private XmlBeanFactory xmlBeanFactory;


    //不进行前置处理
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws Exception {
        return bean;
    }

    //使用基于 AspectJ 表达式及其他配置来实现切面功能
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws Exception {

        //如果我被调用的实例是切面或者增强器，直接返回
        if (bean instanceof AspectJExpressionPointcutAdvisor) {
            return bean;
        }
        if (bean instanceof MethodInterceptor) {
            return bean;
        }
        List<AspectJExpressionPointcutAdvisor> advisors =
                xmlBeanFactory.getBeansForType(AspectJExpressionPointcutAdvisor.class);
        for (AspectJExpressionPointcutAdvisor advisor : advisors) {
            if (advisor.getPointcut().getClassFilter().matchers(bean.getClass())) {
                ProxyFactory proxyFactory = new ProxyFactory();
                proxyFactory.setMethodInterceptor((MethodInterceptor) advisor.getAdvice());
                proxyFactory.setMethodMatcher(advisor.getPointcut().getMethodMatcher());
                TargetSource targetSource = new TargetSource(bean.getClass(), bean.getClass().getInterfaces(), bean);
                proxyFactory.setTargetSource(targetSource);
                return proxyFactory.getProxy();
            }
        }
        return bean;
    }

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws Exception {
        xmlBeanFactory = (XmlBeanFactory) beanFactory;
    }
}
